﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace SimpleORM
{
    public static class ObjectExtension
    {
        public static void TraversalPropertiesInfo(this object source, Func<PropertyInfo, object, object, bool> method, object argument)
        {
            if (method == null || source == null)
                return;

            PropertyInfo[] listPropertyInfo = source.GetType().GetProperties();

            foreach (PropertyInfo pi in listPropertyInfo)
            {
                if (!pi.CanRead)
                    continue;

                object val = pi.GetValue(source, null);
                if (!method(pi, val, argument))
                    return;
            }
        }

        public static void TraversalFieldsInfo(this object source, Func<FieldInfo, object, bool> method)
        {
            if (method == null || source == null)
                return;

            FieldInfo[] listFieldInfo = source.GetType().GetFields();

            foreach (FieldInfo fi in listFieldInfo)
            {
                object val = fi.GetValue(source);
                if (!method(fi, val))
                    return;
            }
        }

        public static void SetPropertyValue(this object source, string propertyName, object propertyValue)
        {
            PropertyInfo pi = source.GetType().GetProperty(propertyName);
            if (pi == null)
                throw new KeyNotFoundException(propertyName);

            pi.SetValue(source, propertyValue, null);
        }

        public static void CopyPropertiesFromExcept(this object target, object source, string[] exceptProperties)
        {
            if (source == null || target == null)
                return;

            if (exceptProperties == null)
                exceptProperties = new string[0];

            Type typeSource = source.GetType();
            Type typeTarget = target.GetType();

            PropertyInfo[] listSourceProperty = typeSource.GetProperties();
            PropertyInfo[] listTargetProperty = typeTarget.GetProperties();

            foreach (PropertyInfo piSource in listSourceProperty)
            {
                if (!piSource.CanRead)
                    continue;

                if (exceptProperties.Contains(piSource.Name))
                    continue;

                try
                {
                    object val = piSource.GetValue(source, null);
                    foreach (PropertyInfo piTarget in listTargetProperty)
                        if (piTarget.Name == piSource.Name &&
                            piTarget.PropertyType.FullName == piSource.PropertyType.FullName &&
                            piTarget.CanWrite)
                        {
                            piTarget.SetValue(target, val, null);
                            break;
                        }
                }
                catch { }
            }
        }
    }
}
